/*
 * ! SAPUI5

		(c) Copyright 2009-2019 SAP SE. All rights reserved
	
 */

// Provides control sap.ui.comp.smartlist.SmartList.
sap.ui.define([
	'sap/ui/comp/library', 'sap/m/library', 'sap/m/VBox', 'sap/m/FlexItemData', 'sap/m/List', 'sap/m/Tree', 'sap/m/Title', 'sap/m/Toolbar', 'sap/m/OverflowToolbar', 'sap/m/ToolbarSpacer', 'sap/m/OverflowToolbarButton', 'sap/ui/comp/odata/ODataModelUtil', 'sap/ui/comp/util/FullScreenUtil', 'sap/ui/core/format/NumberFormat', "sap/base/util/deepEqual"
], function(library, MLibrary, VBox, FlexItemData, List, Tree, Title, Toolbar, OverflowToolbar, ToolbarSpacer, OverflowToolbarButton, ODataModelUtil, FullScreenUtil, NumberFormat, deepEqual) {
	"use strict";

	// shortcut for sap.m.ToolbarDesign
	var ToolbarDesign = MLibrary.ToolbarDesign;

	/**
	 * Constructor for a new smartlist/SmartList.
	 *
	 * @param {string} [sId] ID for the new control, generated automatically if no ID is given
	 * @param {object} [mSettings] initial settings for the new control
	 * @class A smart control to simplify using the <code>sap.m.List</code> and <code>sap.m.Tree</code> controls in list patterns.
	 *        <h3>Overview</h3>
	 *        The <code>SmartList</code> control creates a list or tree based on the configuration specified. There is, however, a difference to
	 *        other smart controls: This control does not use annotations to automatically create its content. Hence, a template must always be
	 *        provided for this control.
	 *        <h3>Structure</h3>
	 *        The <code>SmartList</code> control consists of the following elements:
	 *        <ul>
	 *        <li> <code>OverflowToolbar</code> control: Displays the header and other action buttons. Users can add their own toolbar and buttons
	 *        in the view.</li>
	 *        <li> <code>List</code> or <code>Tree</code> control: The actual list/tree control. Users can also add this in the view with the
	 *        required configuration.</li>
	 *        </ul>
	 *        The <code>entitySet</code> property must be specified to use the control. This attribute is used to fetch the actual data.<br>
	 *        The <code>listItemTemplate</code> aggregation must also be specified with the required item template, such as
	 *        <code>StandardListItem/StandardTreeItem</code>, which will be used during binding.
	 *        <h3><b>Note:</b></h3>
	 *        Most of the attributes/properties are not dynamic and cannot be changed once the control has been initialized.
	 * @extends sap.m.VBox
	 * @author SAP SE
	 * @constructor
	 * @public
	 * @since 1.48
	 * @alias sap.ui.comp.smartlist.SmartList
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var SmartList = VBox.extend("sap.ui.comp.smartlist.SmartList", /** @lends sap.ui.comp.smartlist.SmartList.prototype */
	{
		metadata: {
			library: "sap.ui.comp",
			properties: {
				/**
				 * The entity set name from which to fetch data.<br>
				 * <i>Note:</i><br>
				 * This is not a dynamic UI5 property.
				 *
				 * @since 1.48.0
				 */
				entitySet: {
					type: "string",
					group: "Misc",
					defaultValue: null
				},

				/**
				 * CSV of fields that must be selected when request is sent to the backend.<br>
				 * <i>Note:</i><br>
				 * No validation is done. Please ensure that you do not add spaces or special characters.<br>
				 * This property is only needed when used together with an <code>ODataModel</code>.
				 *
				 * @since 1.48.0
				 */
				selectFields: {
					type: "string",
					group: "Misc",
					defaultValue: null
				},

				/**
				 * CSV of fields that must be expanded when request is sent to the backend.<br>
				 * <i>Note:</i><br>
				 * No validation is done. Please ensure that you do not add spaces or special characters.<br>
				 * This property is only needed when used together with an <code>ODataModel</code>.
				 *
				 * @since 1.48.0
				 */
				expandFields: {
					type: "string",
					group: "Misc",
					defaultValue: null
				},

				/**
				 * If set to <code>true</code> (default), the number of rows is shown along with the header text.<br>
				 * If set to <code>false</code>, the number of rows will not be shown on the user interface.<br>
				 * <i>Note:</i><br>
				 * To avoid sending dedicated OData requests in order to improve your application's performance, you must configure the binding of the
				 * list as required.
				 *
				 * @since 1.48.0
				 */
				showRowCount: {
					type: "boolean",
					group: "Misc",
					defaultValue: true
				},
				/**
				 * Specifies header text that is shown in list.
				 *
				 * @since 1.48.0
				 */
				header: {
					type: "string",
					group: "Misc",
					defaultValue: null
				},
				/**
				 * When set to <code>true</code>, this enables automatic binding of the list using the <code>listBindingPath</code> (if it
				 * exists) or <code>entitySet</code> property. This happens right after the <code>initialise</code> event has been fired.
				 *
				 * @since 1.48.0
				 */
				enableAutoBinding: {
					type: "boolean",
					group: "Misc",
					defaultValue: false
				},
				/**
				 * Specifies the path that is used during the binding of the list. If not specified, the <code>entitySet</code> property is used
				 * instead. (used only if binding is done automatically or when using <code>rebindList</code>)
				 *
				 * @since 1.48.0
				 */
				listBindingPath: {
					type: "string",
					group: "Misc",
					defaultValue: null
				},
				/**
				 * Specifies the type of list to be created in the <code>SmartList</code> control.<br>
				 * <i>Note:</i><br>
				 * If you add a <code>List</code> or <code>Tree</code> to the content of the <code>SmartList</code> control in the view, this
				 * property has no effect.
				 *
				 * @since 1.48.0
				 */
				listType: {
					type: "sap.ui.comp.smartlist.ListType",
					group: "Misc",
					defaultValue: null
				},
				/**
				 * Controls the visibility of the full screen button.
				 *
				 * @since 1.48.0
				 */
				showFullScreenButton: {
					type: "boolean",
					group: "Misc",
					defaultValue: false
				}
			},
			associations: {
				/**
				 * The <code>SmartFilterBar</code> control to be linked to the <code>SmartList</code> control. Some events of the
				 * <code>SmartFilterBar</code> control are then used to fetch data, show overlay etc.
				 *
				 * @since 1.48.0
				 */
				smartFilter: {
					type: "sap.ui.core.Control"
				}
			},
			aggregations: {
				/**
				 * Specifies the template that is used for the inner <code>List</code> or <code>Tree</code> control.<br>
				 * <b>Note:</b><br>
				 * This template is used when binding the <code>items</code> of <code>sap.m.List</code> or <code>sap.m.Tree</code> control, and
				 * will not be available in the <code>SmartList</code> control once the binding has been done.
				 *
				 * @since 1.48.0
				 */
				listItemTemplate: {
					type: "sap.m.ListItemBase",
					multiple: false
				}
			},
			events: {
				/**
				 * Event fired once the control has been initialized.
				 *
				 * @since 1.48.0
				 */
				initialise: {},
				/**
				 * Event fired right before the binding is being done.
				 *
				 * @param {sap.ui.base.Event} oControlEvent
				 * @param {sap.ui.base.EventProvider} oControlEvent.getSource
				 * @param {object} oControlEvent.getParameters
				 * @param {object} oControlEvent.getParameters.bindingParams The bindingParams object contains filters, sorters and other
				 *        binding-related information for the list
				 * @param {boolean} oControlEvent.getParameters.bindingParams.preventTableBind If set to <code>true</code> by the listener, binding
				 *        is prevented
				 * @param {sap.ui.model.Filter[]} oControlEvent.getParameters.bindingParams.filters The combined filter array containing a set of
				 *        <code>sap.ui.model.Filter</code> instances from the <code>SmartList</code> and <code>SmartFilter</code> controls; can
				 *        be modified by users to influence filtering
				 * @param {sap.ui.model.Sorter[]} oControlEvent.getParameters.bindingParams.sorter An array containing a set of
				 *        <code>sap.ui.model.Sorter</code> instances from the <code>SmartList</code> control (personalization); can be modified by
				 *        users to influence sorting
				 * @since 1.48.0
				 */
				beforeRebindList: {},
				/**
				 * Event fired when data is received after binding. The event is usually only fired if the binding for the list is done by the
				 * <code>SmartList</code> control itself.
				 *
				 * @since 1.48.0
				 */
				dataReceived: {}
			}
		},
		renderer: {
			apiVersion: 2
		},
		constructor: function() {
			VBox.apply(this, arguments);
			this.addStyleClass("sapUiCompSmartList");
			this._createToolbar();
			this._createList();
			this.attachModelContextChange(this._initialiseMetadata, this);
		}
	});
	// default aggregation
	SmartList.prototype._sAggregation = "items";

	SmartList.prototype.setHeader = function(sText) {
		this.setProperty("header", sText, true);
		this._refreshHeaderText();
		return this;
	};

	SmartList.prototype.setShowRowCount = function(bShow) {
		this.setProperty("showRowCount", bShow, true);
		this._refreshHeaderText();
		return this;
	};

	SmartList.prototype.setShowFullScreenButton = function(bShowFullScreenButton) {
		this.setProperty("showFullScreenButton", bShowFullScreenButton, true);
		if (this._oFullScreenButton) {
			this._oFullScreenButton.setVisible(this.getShowFullScreenButton());
		}
		return this;
	};

	SmartList.prototype.setEntitySet = function(sEntitySetName) {
		this.setProperty("entitySet", sEntitySetName);
		this._initialiseMetadata();
		return this;
	};

	/**
	 * sets the header text
	 *
	 * @private
	 */
	SmartList.prototype._refreshHeaderText = function() {
		if (!this._headerText) {
			return;
		}

		var sText = this.getHeader();
		var bTextVisible = !!sText;
		this._headerText.setVisible(bTextVisible);

		if (bTextVisible && this.getShowRowCount()) {
			var iRowCount = parseInt(this._getRowCount());
			if (!this._oNumberFormatter) {
				this._oNumberFormatter = NumberFormat.getFloatInstance();
			}
			var sValue = this._oNumberFormatter.format(iRowCount);
			sText += " (" + sValue + ")";
		}
		this._headerText.setText(sText);
	};

	/**
	 * creates the fullscreen button and adds it into toolbar
	 */
	SmartList.prototype._addFullScreenButton = function() {
		// always remove content first
		if (this._oFullScreenButton) {
			this._oToolbar.removeContent(this._oFullScreenButton);
		}
		if (this.getShowFullScreenButton()) {
			if (!this._oFullScreenButton) {
				this._oFullScreenButton = new OverflowToolbarButton(this.getId() + "-btnFullScreen", {
					press: function() {
						this._toggleFullScreen(!this.bFullScreen);
					}.bind(this)
				});
			}
			this._toggleFullScreen(this.bFullScreen, true);
			this._oToolbar.addContent(this._oFullScreenButton);
		}
	};
	/**
	 * creates the toolbar
	 *
	 * @private
	 */
	SmartList.prototype._createToolbar = function() {
		var aContent, iLen, oToolbar;
		if (!this._oToolbar) {
			aContent = this.getItems();
			iLen = aContent ? aContent.length : 0;
			// Check if a Toolbar already exists in the content (Ex: from view.xml)
			while (iLen--) {
				oToolbar = aContent[iLen];
				if (oToolbar instanceof Toolbar) {
					break;
				}
				oToolbar = null;
			}
			if (oToolbar) {
				this._oToolbar = oToolbar;
			} else {
				this._oToolbar = new OverflowToolbar(this.getId() + "-toolbar", {
					design: ToolbarDesign.Transparent
				});
				this.insertItem(this._oToolbar, 0);
			}
			// Set layoutData on the toolbar, if none already exists
			if (!this._oToolbar.getLayoutData()) {
				this._oToolbar.setLayoutData(new FlexItemData({
					shrinkFactor: 0
				}));
			}
		}
	};
	/**
	 * Toggles between fullscreen and normal view mode
	 *
	 * @param {boolean} bValue - the new value of FullScreen
	 * @param {boolean} bForced - whether setting FullScreen is forced
	 * @private
	 */
	SmartList.prototype._toggleFullScreen = function(bValue, bForced) {
		var resourceB = sap.ui.getCore().getLibraryResourceBundle("sap.ui.comp"), sText;

		if (!this._oFullScreenButton || (bValue === this.bFullScreen && !bForced)) {
			return;
		}

		this.bFullScreen = bValue;

		FullScreenUtil.toggleFullScreen(this, this.bFullScreen, this._oFullScreenButton, this._toggleFullScreen);

		sText = this.bFullScreen ? resourceB.getText("CHART_MINIMIZEBTN_TOOLTIP") : resourceB.getText("CHART_MAXIMIZEBTN_TOOLTIP");
		this._oFullScreenButton.setTooltip(sText);
		this._oFullScreenButton.setText(sText);
		this._oFullScreenButton.setIcon(this.bFullScreen ? "sap-icon://exit-full-screen" : "sap-icon://full-screen");
	};

	/**
	 * creates the toolbar content
	 *
	 * @private
	 */
	SmartList.prototype._createToolbarContent = function() {
		if (!this._oToolbar) {
			this._createToolbar();
		}
		// insert the items in the custom toolbar in reverse order => insert always at position 0
		this._addHeaderToToolbar();

		// add spacer to toolbar
		this._addSpacerToToolbar();

		// First show Display/Edit icon, then Personalisation and finally Excel Export
		this._addFullScreenButton();

		this._oToolbar.addStyleClass("sapMTBHeader-CTX");
	};

	/**
	 * adds the header line to the toolbar
	 *
	 * @private
	 */
	SmartList.prototype._addHeaderToToolbar = function() {
		// always remove content first
		if (this._headerText) {
			this._oToolbar.removeContent(this._headerText);
		}

		if (!this._headerText) {
			this._headerText = new Title(this.getId() + "-header");
			this._headerText.addStyleClass("sapMH4Style");
			this._headerText.addStyleClass("sapUiCompSmartTableHeader");
		}

		this._refreshHeaderText();
		this._oToolbar.insertContent(this._headerText, 0);
	};

	/**
	 * adds a spacer to the toolbar
	 *
	 * @private
	 */
	SmartList.prototype._addSpacerToToolbar = function() {
		var bFoundSpacer = false, aItems = this._oToolbar.getContent(), i, iLength;
		if (aItems) {
			iLength = aItems.length;
			i = 0;
			for (i; i < iLength; i++) {
				if (aItems[i] instanceof ToolbarSpacer) {
					bFoundSpacer = true;
					break;
				}
			}
		}

		if (!bFoundSpacer) {
			this._oToolbar.addContent(new ToolbarSpacer(this.getId() + "-toolbarSpacer"));
		}
	};

	/**
	 * gets list's row count
	 *
	 * @private
	 * @returns {int} the row count
	 */
	SmartList.prototype._getRowCount = function() {
		var oRowBinding = this._getRowBinding();

		if (!oRowBinding) {
			return 0;
		}

		var iRowCount = 0;
		if (oRowBinding.getTotalSize) {
			iRowCount = oRowBinding.getTotalSize();
		} else {
			iRowCount = oRowBinding.getLength();
		}

		if (iRowCount < 0 || iRowCount === "0") {
			iRowCount = 0;
		}

		return iRowCount;
	};

	/**
	 * returns the row/items binding of the currently used internal list
	 *
	 * @private
	 * @returns {sap.ui.model.Binding} the row/items binding
	 */
	SmartList.prototype._getRowBinding = function() {
		if (this._oList) {
			return this._oList.getBinding(this._sAggregation);
		}
	};

	/**
	 * Initialises the OData metadata necessary to create the list
	 *
	 * @private
	 */
	SmartList.prototype._initialiseMetadata = function() {
		if (!this.bIsInitialised) {
			ODataModelUtil.handleModelInit(this, this._onMetadataInitialised);
		}
	};

	/**
	 * Called once the necessary Model metadata is available
	 *
	 * @private
	 */
	SmartList.prototype._onMetadataInitialised = function() {
		this._bMetaModelLoadAttached = false;
		if (!this.bIsInitialised) {
			this.detachModelContextChange(this._initialiseMetadata, this);
			// Indicates the control is initialised and can be used in the initialise event/otherwise!
			this.bIsInitialised = true;
			this._listenToSmartFilter();
			this._createToolbarContent();
			this._createContent();
			this.fireInitialise();
			this._checkAndTriggerBinding();
		}
	};

	/**
	 * Check if control needs to be bound and trigger binding accordingly.
	 *
	 * @private
	 */
	SmartList.prototype._checkAndTriggerBinding = function() {
		if (!this._bAutoBindingTriggered) {
			this._bAutoBindingTriggered = true;
			if (this.getEnableAutoBinding()) {
				if (this._oSmartFilter) {
					this._oSmartFilter.search();
				} else {
					this._reBindList();
				}
			}
		}
	};

	/**
	 * Listen to changes on the corresponding SmartFilter (if any)
	 *
	 * @private
	 */
	SmartList.prototype._listenToSmartFilter = function() {
		var sSmartFilterId = null;
		// Register for SmartFilter Search
		sSmartFilterId = this.getSmartFilter();
		if (typeof sSmartFilterId === "string") {
			this._oSmartFilter = sap.ui.getCore().byId(sSmartFilterId);
		} else {
			this._oSmartFilter = sSmartFilterId;
		}

		if (this._oSmartFilter) {
			this._oSmartFilter.attachSearch(this._reBindList, this);
			this._oSmartFilter.attachFilterChange(this._filterChangeEvent, this);
			this._oSmartFilter.attachCancel(this._cancelEvent, this);

			// Set initial empty text only if a valid SmartFilter is found
			this._setNoDataText(sap.ui.getCore().getLibraryResourceBundle("sap.ui.comp").getText("SMARTTABLE_NO_DATA"));
		}
	};

	SmartList.prototype._filterChangeEvent = function() {
		if (this._isListBound() && this._oSmartFilter && !this._oSmartFilter.getLiveMode()) {
			this._showOverlay(true);
		}
	};

	SmartList.prototype._cancelEvent = function() {
		if (this._oSmartFilter && !this._oSmartFilter.getLiveMode()) {
			this._showOverlay(false);
		}
	};

	/**
	 * sets the ShowOverlay property on the inner list, fires the ShowOverlay event
	 *
	 * @param {boolean} bShow true to display the overlay, otherwise false
	 * @private
	 */
	SmartList.prototype._showOverlay = function(bShow) {
		// to be implemented --> Not supported by the List/Tree
	};

	/**
	 * This can be used to trigger binding on the list used in the SmartList
	 *
	 * @param {boolean} bForceRebind - force bind call to be triggered on the inner list
	 * @protected
	 */
	SmartList.prototype.rebindList = function(bForceRebind) {
		this._reBindList(null, bForceRebind);
	};

	/**
	 * Re-binds the list
	 *
	 * @param {Object} mEventParams - the event parameters
	 * @param {boolean} bForceRebind - force bind call to be triggered on the list
	 * @private
	 */
	SmartList.prototype._reBindList = function(mEventParams, bForceRebind) {
		var oListBinding, sListBindingPath, aSmartFilters, aFilters, aSorters, mParameters = {}, mBindingParams = {
			preventListBind: false
		};

		// Get Filters and parameters from SmartFilter
		if (this._oSmartFilter) {
			aSmartFilters = this._oSmartFilter.getFilters();
			mParameters = this._oSmartFilter.getParameters() || {};
		}
		aFilters = aSmartFilters;

		// No sorters yet!
		if (!aSorters) {
			aSorters = [];
		}

		// Select parameters
		mParameters["select"] = this.getSelectFields();
		// expand parameters
		mParameters["expand"] = this.getExpandFields();

		// Enable batch requests (by default)
		mParameters["useBatchRequests"] = true;

		mBindingParams.filters = aFilters;
		mBindingParams.sorter = aSorters;
		mBindingParams.parameters = mParameters;
		mBindingParams.length = undefined;
		mBindingParams.startIndex = undefined;
		// fire event to enable user modification of certain binding options (Ex: Filters)
		this.fireBeforeRebindList({
			bindingParams: mBindingParams
		});

		if (!mBindingParams.preventListBind) {
			aSorters = mBindingParams.sorter;
			aFilters = mBindingParams.filters;
			mParameters = mBindingParams.parameters;

			sListBindingPath = this.getListBindingPath() || ("/" + this.getEntitySet());
			this._bDataLoadPending = true;
			this._bIgnoreChange = false; // if a 2nd request is sent while the 1st one is in progress the dataReceived event may not be fired!
			// Only check if binding exists, if list is not being forcefully rebound
			if (!bForceRebind) {
				oListBinding = this._oList.getBinding(this._sAggregation);
				if (oListBinding && oListBinding.mParameters) {
					// Check if binding needs to be redone!
					// Evaluate to true if:
					// binding parameters change -or- custom binding parameters change -or- if length, startIndex or listBindingPath change!
					bForceRebind = !(deepEqual(mParameters, oListBinding.mParameters, true) && deepEqual(mParameters.custom, oListBinding.mParameters.custom) && !mBindingParams.length && !mBindingParams.startIndex && sListBindingPath === oListBinding.getPath());
				}
			}

			// do the binding if no binding is already present or if it is being forced!
			if (!oListBinding || !this._bIsListBound || bForceRebind) {
				this._oList.bindItems({
					path: sListBindingPath,
					filters: aFilters,
					sorter: aSorters,
					parameters: mParameters,
					length: mBindingParams.length,
					startIndex: mBindingParams.startIndex,
					template: this._oTemplate,
					events: {
						dataRequested: function() {
							this._bIgnoreChange = true;
						}.bind(this),
						dataReceived: function(mEventParams) {
							this._bIgnoreChange = false;
							this._onDataLoadComplete(mEventParams, true);
							// notify any listeners about dataReceived
							this.fireDataReceived(mEventParams);
						}.bind(this),
						change: function(mEventParams) {
							if (this._bIgnoreChange) {
								return;
							}
							var sReason, bForceUpdate = false;
							sReason = (mEventParams && mEventParams.getParameter) ? mEventParams.getParameter("reason") : undefined;
							// Force update state if reason for binding change is "context" or "filter" -or- not defined
							if (!sReason || sReason === "filter" || sReason === "context") {
								bForceUpdate = true;
							}
							if (sReason === "change" || bForceUpdate) {
								this._onDataLoadComplete(mEventParams, bForceUpdate);
							}
						}.bind(this)
					}
				});
				// Flag to indicate if list was bound (data fetch triggered) at least once
				this._bIsListBound = true;
			} else {
				oListBinding.sort(aSorters);
				oListBinding.filter(aFilters, "Application");
			}
			this._showOverlay(false);
		}
	};

	/**
	 * Called once data is loaded in the binding (i.e. either backend fetch or once change event is fired)
	 *
	 * @param {Object} mEventParams - the event parameters
	 * @param {boolean} bForceUpdate - force update
	 * @private
	 */
	SmartList.prototype._onDataLoadComplete = function(mEventParams, bForceUpdate) {
		if (this._bDataLoadPending || bForceUpdate) {
			this._bDataLoadPending = false;
			// Update No data text (once) only if list has no results!
			if (!this._bNoDataUpdated && !this._getRowCount()) {
				this._bNoDataUpdated = true;
				this._setNoDataText();
			}
			this._refreshHeaderText();
		}
	};

	/**
	 * Returns true if the inner UI5 list was bound at least once by the SmartList -or- if binding was done by the app.
	 *
	 * @returns {boolean} whether the inner UI5 list is bound
	 * @private
	 */
	SmartList.prototype._isListBound = function() {
		if (this._bIsListBound) {
			return true;
		}
		if (this._oList) {
			return this._oList.isBound(this._sAggregation);
		}
		return false;
	};

	/**
	 * Sets the no data text to the internal list
	 *
	 * @param {string} sOverwriteText - optional text to set on the list
	 * @private
	 */
	SmartList.prototype._setNoDataText = function(sOverwriteText) {
		if (this._oList) {
			if (!sOverwriteText) {
				sOverwriteText = sap.ui.getCore().getLibraryResourceBundle("sap.ui.comp").getText("SMARTTABLE_NO_RESULTS");
			}
			this._oList.setNoDataText(sOverwriteText);
		}
	};

	/**
	 * Creates the content based on the metadata/configuration
	 *
	 * @private
	 */
	SmartList.prototype._createContent = function() {
		if (!this._oTemplate) {
			this._oTemplate = this.getListItemTemplate();
		}
	};

	/**
	 * Creates a list based on the configuration, if necessary. This also prepares the methods to be used based on the list type.
	 *
	 * @private
	 */
	SmartList.prototype._createList = function() {
		var aContent = this.getItems(), iLen = aContent ? aContent.length : 0, oList, sId;
		// Check if a List already exists in the content (Ex: from view.xml)
		while (iLen--) {
			oList = aContent[iLen];
			if (oList instanceof List || oList instanceof Tree) {
				break;
			}
			oList = null;
		}

		// If a List exists determine its type else create one based on the listItemType property!
		if (oList) {
			this._oList = oList;
			if (oList instanceof Tree) {
				this._isTree = true;
			} else {
				this._isList = true;
			}
			// get the item template from the view
			this._oTemplate = (oList.getItems() && oList.getItems().length > 0) ? oList.getItems()[0] : this.getListItemTemplate();
			oList.removeAllItems();
		} else {
			sId = this.getId() + "-ui5list";
			// Create list/tree
			if (this.getListType() === "Tree") {
				this._oList = new Tree(sId);
				this._isTree = true;
			} else {
				this._oList = new List(sId, {
					growing: true,
					growingScrollToLoad: true
				});
				this._isList = true;
			}
			this.insertItem(this._oList, 2);
		}

		if (!this._oList.getLayoutData()) {
			this._oList.setLayoutData(new FlexItemData({
				growFactor: 1,
				baseSize: "auto"
			}));
		}
		// Set ariaLabelledBy on the inner UI5 list
		this._oList.addAriaLabelledBy(this.getId() + "-header");

	};

	/**
	 * Returns the <code>List</code> or <code>Tree</code> used internally.
	 *
	 * @public
	 * @returns {object} the control
	 */
	SmartList.prototype.getList = function() {
		return this._oList;
	};

	/**
	 * Checks whether the control is initialized.
	 *
	 * @returns {boolean} returns whether control has already been initialized
	 * @protected
	 */
	SmartList.prototype.isInitialised = function() {
		return !!this.bIsInitialised;
	};

	/**
	 * Cleans up the control
	 *
	 * @protected
	 */
	SmartList.prototype.exit = function() {
		// Cleanup smartFilter events as it can be used again stand-alone without being destroyed!
		if (this._oSmartFilter) {
			this._oSmartFilter.detachSearch(this._reBindList, this);
			this._oSmartFilter.detachFilterChange(this._filterChangeEvent, this);
			this._oSmartFilter.detachCancel(this._cancelEvent, this);
			this._oSmartFilter = null;
		}

		FullScreenUtil.cleanUpFullScreen(this);

		// Destroy the template as it is not part of the UI5 list as long as it is not bound!
		if (!this._bIsListBound && this._oTemplate) {
			this._oTemplate.destroy();
		}
		this._oTemplate = null;
		this._oToolbar = null;
		this._headerText = null;
		this._oFullScreenButton = null;
		this._oNumberFormatter = null;
		this._oList = null;
	};

	return SmartList;

}, /* bExport= */true);